/*
 *    Copyright (c) 2018-2025, shenghua All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: shenghua
 */

package com.chen.common.feign.config;

import com.chen.root.constant.SecurityCons;
import com.chen.root.property.GatewaySecurityProperties;
import feign.Feign;
import feign.Request;
import feign.RequestInterceptor;
import feign.slf4j.Slf4jLogger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClientsRegistrarConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpHeaders;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * @author ChenJinLong
 * <p>
 * feign 自动化配置
 */
@Slf4j
@Configuration
@ConditionalOnClass(Feign.class)
@Import(FeignClientsRegistrarConfig.class)
@AutoConfigureAfter(EnableFeignClients.class)
public class FeignAutoConfiguration {

	@Resource
	private GatewaySecurityProperties gatewaySecurity;

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnAvailableEndpoint
	public FeignClientEndpoint feignClientEndpoint(ApplicationContext context) {
		return new FeignClientEndpoint(context);
	}

	/**
	 * 全局配置feign传递token
	 */
	@Bean
	public RequestInterceptor requestInterceptor() {
		return requestTemplate -> {
			log.info("Feign 远程请求 [{}]: {}{}", requestTemplate.method(), requestTemplate.feignTarget().url(), requestTemplate.url());
			ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
			if (attributes != null) {
				HttpServletRequest request = attributes.getRequest();
				// 将token信息放入header中
				requestTemplate.header(HttpHeaders.AUTHORIZATION, request.getHeader(HttpHeaders.AUTHORIZATION));
			}

			if (gatewaySecurity.getEnable()){
				// 网关安全标识码
				requestTemplate.header(SecurityCons.GATEWAY_SECURITY_CODE, gatewaySecurity.getSecurityCode());
			}
		};
	}

	/**
	 * Feign 客户端的日志记录，默认级别为NONE
	 * Logger.Level 的具体级别如下：
	 * NONE：不记录任何信息
	 * BASIC：仅记录请求方法、URL以及响应状态码和执行时间
	 * HEADERS：除了记录 BASIC级别的信息外，还会记录请求和响应的头信息
	 * FULL：记录所有请求与响应的明细，包括头信息、请求体、元数据
	 */
	@Bean
	public feign.Logger logger() {
		return new Slf4jLogger();
	}

	/**
	 * 全局超时时间配置, 单位：秒
	 */
	@Bean
	public Request.Options options(){
		// 第一个参数：连接超时配置; 第二个参数：连接成功，但逻辑处理超时配置
		return new Request.Options(30, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);
	}

	/**
	 * 方法级别的超时时间配置增强
	 */
	@Bean
	public FeignOptionAop feignOptionAop(){
		return new FeignOptionAop();
	}

}